home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / JSplitPane.java < prev    next >
Text File  |  1998-06-30  |  30KB  |  862 lines

  1. /*
  2.  * @(#)JSplitPane.java    1.38 98/04/08
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20.  
  21. package com.sun.java.swing;
  22.  
  23. import java.awt.*;
  24. import com.sun.java.swing.border.Border;
  25. import com.sun.java.swing.plaf.*;
  26. import com.sun.java.accessibility.*;
  27.  
  28. /**
  29.  * JSplitPane is used to divide two (and only two) Components. The two
  30.  * Components are graphically divided based on the look and feel
  31.  * implementation, and the two Components can then be interactively 
  32.  * resized by the user.
  33.  * <p>
  34.  * The two Components can be aligned left to right using
  35.  * <code>JSplitPane.HORIZONTAL_SPLIT</code>, or top to bottom using 
  36.  * <code>JSplitPane.VERTICAL_SPLIT</code>.
  37.  * The preferred way to change the size of the Components is to invoke
  38.  * <code>setDividerLocation</code> where <code>location</code> is either
  39.  * the new x or y position, depending on the orientation of the
  40.  * JSplitPane. If one component changes, JSplitPane also attempts to 
  41.  * reposition the other component.
  42.  * <p>
  43.  * To resize the Components to their preferred sizes invoke
  44.  * <code>resetToPreferredSizes</code>.
  45.  * <p>
  46.  * When the user is resizing the Components the minimum size of the
  47.  * Components is used to determine the maximum/minimum position the
  48.  * Components can be set to. So that if the minimum size of the two
  49.  * components is greater than the size of the splitpane the divider
  50.  * will not allow you to resize it. To alter the minimum size of a
  51.  * JComponent, see <code>JComponent.setMinimumSize</code>.
  52.  * <p>
  53.  * For the keyboard keys used by this component in the standard Look and
  54.  * Feel (L&F) renditions, see the
  55.  * <a href="doc-files/Key-Index.html#JSplitPane">JSplitPane</a> key assignments.
  56.  * <p>
  57.  * Warning: serialized objects of this class will not be compatible with
  58.  * future swing releases.  The current serialization support is appropriate
  59.  * for short term storage or RMI between Swing1.0 applications.  It will
  60.  * not be possible to load serialized Swing1.0 objects with future releases
  61.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  62.  * baseline for the serialized form of Swing objects.
  63.  *
  64.  * @see #setDividerLocation
  65.  * @see #resetToPreferredSizes
  66.  * @see JComponent.setMinimumSize
  67.  *
  68.  * @version 1.38 04/08/98
  69.  * @author Scott Violet
  70.  */
  71. public class JSplitPane extends JComponent implements Accessible
  72. {
  73.     /** Vertical split indicates the Components are split along the
  74.       * y axis, eg the two Components will be split one on top of the other. */
  75.     public final static int        VERTICAL_SPLIT = 0;
  76.     /** Horizontal split indicates the Components are split along the
  77.       * x axis, eg the two Components will be split one to the left of the
  78.       * other. */
  79.     public final static int        HORIZONTAL_SPLIT = 1;
  80.  
  81.     /** Used to add a Component to the left of the other Component. */
  82.     public final static String     LEFT = "left";
  83.     /** Used to add a Component to the right of the other Component. */
  84.     public final static String     RIGHT = "right";
  85.     /** Used to add a Component above the other Component. */
  86.     public final static String     TOP = "top";
  87.     /** Used to add a Component below the other Component. */
  88.     public final static String     BOTTOM = "bottom";
  89.     /** Used to add a Component that will represent the divider. */
  90.     public final static String     DIVIDER = "divider";
  91.  
  92.     /** Bound property name for orientation (horizontal or vertical). */
  93.     public final static String ORIENTATION_PROPERTY = "orientation";
  94.     /** Bound property name for continuousLayout. */
  95.     public final static String CONTINUOUS_LAYOUT_PROPERTY = "continuousLayout";
  96.     /** Bound property name for border. */
  97.     public final static String DIVIDER_SIZE_PROPERTY = "dividerSize";
  98.     /** Bound property for oneTouchExpandable. */
  99.     public final static String ONE_TOUCH_EXPANDABLE_PROPERTY = 
  100.                                "oneTouchExpandable";
  101.     /** Bound property for lastLocation. */
  102.     public final static String LAST_DIVIDER_LOCATION_PROPERTY =
  103.                                "lastDividerLocation";
  104.  
  105.     /** How the views are split. */
  106.     protected int            orientation;
  107.  
  108.     /** Whether or not the views are continuously redisplayed while
  109.       * resizing. */
  110.     protected boolean        continuousLayout;
  111.  
  112.     /** The left or top component. */
  113.     protected Component      leftComponent;
  114.  
  115.     /* The right or bottom component. */
  116.     protected Component      rightComponent;
  117.  
  118.     /** Size of the divider. */
  119.     protected int            dividerSize;
  120.  
  121.     /** Is a little widget provided to quickly expand/collapse the
  122.      * split pane? */
  123.     protected boolean        oneTouchExpandable;
  124.  
  125.     /** Previous location of the split pane. */
  126.     protected int            lastDividerLocation;
  127.  
  128.     /**
  129.       * Returns a new JSplitPane configured to arrange the child
  130.       * components side-by-side horizontally with no continuous 
  131.       * layout, using two buttons for the compoents.
  132.       */
  133.     public JSplitPane() {
  134.         this(JSplitPane.HORIZONTAL_SPLIT, false, new JButton("left button"),
  135.              new JButton("right button"));
  136.     }
  137.  
  138.     /**
  139.       * Returns a new JSplitPane configured with the specified orientation
  140.       * and no continuous layout.
  141.       *
  142.       * @param newOrientation an int specifying the horizontal or vertical
  143.       *        orientation
  144.       */
  145.     public JSplitPane(int newOrientation) {
  146.         this(newOrientation, false);
  147.     }
  148.  
  149.     /**
  150.       * Returns a new JSplitPane with the specified orientation and
  151.       * redrawing style.
  152.       *
  153.       * @param newOrientation an int specifying the horizontal or vertical
  154.       *        orientation
  155.       * @param newContinuousLayout  a boolean, true for the components to 
  156.       *        redraw continuously as the divider changes position, false
  157.       *        to wait until the divider position stops changing to redraw
  158.       */
  159.     public JSplitPane(int newOrientation, boolean newContinuousLayout) {
  160.         this(newOrientation, newContinuousLayout, null, null);
  161.     }
  162.  
  163.     /**
  164.       * Returns a new JSplitPane with the specified orientation and
  165.       * with the specifiied components that does not do continuous
  166.       * redrawing.
  167.       *
  168.       * @param newOrientation an int specifying the horizontal or vertical
  169.       *        orientation
  170.       * @param newContinuousLayout  a boolean, true for the components to 
  171.       *        redraw continuously as the divider changes position, false
  172.       *        to wait until the divider position stops changing to redraw
  173.       * @param newLeftComponent the Component that will appear on the left
  174.       *        of a horizontally-split pane, or at the top of a
  175.       *        vertically-split pane.
  176.       */
  177.     public JSplitPane(int newOrientation,
  178.                       Component newLeftComponent, Component newRightComponent){
  179.         this(newOrientation, false, newLeftComponent, newRightComponent);
  180.     }
  181.  
  182.     /**
  183.       * Returns a new JSplitPane with the specified orientation and
  184.       * redrawing style, and with the specifiied components.
  185.       *
  186.       * @param newOrientation an int specifying the horizontal or vertical
  187.       *        orientation
  188.       * @param newContinuousLayout  a boolean, true for the components to 
  189.       *        redraw continuously as the divider changes position, false
  190.       *        to wait until the divider position stops changing to redraw
  191.       * @param newLeftComponent the Component that will appear on the left
  192.       *        of a horizontally-split pane, or at the top of a
  193.       *        vertically-split pane.
  194.       */
  195.     public JSplitPane(int newOrientation, boolean newContinuousLayout,
  196.                       Component newLeftComponent, Component newRightComponent){
  197.         super();
  198.  
  199.         setLayout(null);
  200.         orientation = newOrientation;
  201.         if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT)
  202.             throw new IllegalArgumentException("cannot create JSplitPane, orientation must be one of JSplitPane.HORIZONTAL_SPLIT or JSplitPane.VERTICAL_SPLIT");
  203.         continuousLayout = newContinuousLayout;
  204.         if (newLeftComponent != null)
  205.             setLeftComponent(newLeftComponent);
  206.         if (newRightComponent != null)
  207.             setRightComponent(newRightComponent);
  208.         updateUI();
  209.  
  210.     }
  211.  
  212.     /**
  213.      * Sets the L&F object that renders this component.
  214.      *
  215.      * @param ui  the SplitPaneUI L&F object
  216.      * @see UIDefaults#getUI
  217.      */
  218.     public void setUI(SplitPaneUI ui) {
  219.         if ((SplitPaneUI)this.ui != ui) {
  220.             super.setUI(ui);
  221.             invalidate();
  222.         //    System.out.println ("setUI"  );
  223.         //    System.out.println ("Divider Size " + getDividerSize()  );
  224.         }
  225.     }
  226.  
  227.     /**
  228.      * Returns the SplitPaneUI that is providing the current look and 
  229.      * feel. 
  230.      *
  231.      * @return the SplitPaneUI object that renders this component
  232.      * @beaninfo
  233.      *      expert: true
  234.      *  description: The L&F object that renders this component.
  235.      */
  236.     public SplitPaneUI getUI() {
  237.         return (SplitPaneUI)ui;
  238.     }
  239.  
  240.     /**
  241.      * Notification from the UIManager that the L&F has changed. 
  242.      * Replaces the current UI object with the latest version from the 
  243.      * UIManager.
  244.      *
  245.      * @see JComponent#updateUI
  246.      */
  247.     public void updateUI() {
  248.         setUI((SplitPaneUI)UIManager.getUI(this));
  249.         invalidate();
  250.     }
  251.  
  252.  
  253.     /**
  254.      * Returns the name of the L&F class that renders this component.
  255.      *
  256.      * @return "SplitPaneUI"
  257.      * @see JComponent#getUIClassID
  258.      * @see UIDefaults#getUI
  259.      * @beaninfo
  260.      *        expert: true
  261.      *   description: A string that specifies the name of the L&F class.
  262.      */
  263.     public String getUIClassID() {
  264.         return "SplitPaneUI";
  265.     }
  266.  
  267.  
  268.     /**
  269.      * Sets the size of the divider.
  270.      *
  271.      * @param newSize an int giving the size of the divider in pixels
  272.      * @beaninfo
  273.      *        bound: true
  274.      *  description: The size of the divider.
  275.      */
  276.     public void setDividerSize(int newSize) {
  277.         int           oldSize = dividerSize;
  278.  
  279.         if (oldSize != newSize) {
  280.             dividerSize = newSize;
  281.             firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, newSize);
  282.         }
  283.     }
  284.  
  285.     /**
  286.      * Returns the size of the divider.
  287.      *
  288.      * @return an int giving the size of the divider in pixels
  289.      */
  290.     public int getDividerSize() {
  291.         return dividerSize;
  292.     }
  293.  
  294.     /**
  295.      * Sets the component to the left (or above) the divider.
  296.      *
  297.      * @param comp the Component to display in that position
  298.      */
  299.     public void setLeftComponent(Component comp) {
  300.         if (comp == null) {
  301.             if (leftComponent != null) {
  302.                 remove(leftComponent);
  303.                 leftComponent = null;
  304.             }
  305.         } else {
  306.             add(comp, JSplitPane.LEFT);
  307.         }
  308.     }
  309.  
  310.     /**
  311.      * Returns the component to the left (or above) the divider.
  312.      *
  313.      * @return the Component displayed in that position
  314.      * @beaninfo
  315.      *  preferred: true
  316.      *  description: The component to the left (or above) the divider.
  317.      */
  318.     public Component getLeftComponent() {
  319.         return leftComponent;
  320.     }
  321.  
  322.     /**
  323.      * Sets the component above, or to the left of the divider.
  324.      *
  325.      * @param comp the Component to display in that position
  326.      * @beaninfo
  327.      *  description: The component above, or to the left of the divider.
  328.      */
  329.     public void setTopComponent(Component comp) {
  330.         setLeftComponent(comp);
  331.     }
  332.  
  333.     /**
  334.      * Returns the component above, or to the left of the divider.
  335.      *
  336.      * @return the Component displayed in that position
  337.      */
  338.     public Component getTopComponent() {
  339.         return leftComponent;
  340.     }
  341.  
  342.     /**
  343.      * Sets the component to the right (or below) the divider.
  344.      *
  345.      * @param comp the Component to display in that position
  346.      * @beaninfo
  347.      *    preferred: true
  348.      *  description: The component to the right (or below) the divider.
  349.      */
  350.     public void setRightComponent(Component comp) {
  351.         if (comp == null) {
  352.             if (rightComponent != null) {
  353.                 remove(rightComponent);
  354.                 rightComponent = null;
  355.             }
  356.         } else {
  357.             add(comp, JSplitPane.RIGHT);
  358.         }
  359.     }
  360.  
  361.     /**
  362.      * Returns the component to the right (or below) the divider.
  363.      *
  364.      * @return the Component displayed in that position
  365.      */
  366.     public Component getRightComponent() {
  367.         return rightComponent;
  368.     }
  369.  
  370.     /**
  371.      * Sets the component below, or to the right of the divider.
  372.      *
  373.      * @param comp the Component to display in that position
  374.      * @beaninfo
  375.      *  description: The component below, or to the right of the divider.
  376.      */
  377.     public void setBottomComponent(Component comp) {
  378.         setRightComponent(comp);
  379.     }
  380.  
  381.     /**
  382.      * Returns the component below, or to the right of the divider.
  383.      *
  384.      * @return the Component displayed in that position
  385.      */
  386.     public Component getBottomComponent() {
  387.         return rightComponent;
  388.     }
  389.  
  390.     /**
  391.      * Determines whether the JSplitPane provides a UI widget
  392.      * on the divider to quickly expand/collapse the divider.
  393.      *
  394.      * @param newValue a boolean, where true means to provide a
  395.      *        collapse/expand widget
  396.      * @beaninfo
  397.      *        bound: true
  398.      *  description: UI widget on the divider to quickly 
  399.      *               expand/collapse the divider.
  400.      */
  401.     public void setOneTouchExpandable(boolean newValue) {
  402.         boolean           oldValue = oneTouchExpandable;
  403.  
  404.         oneTouchExpandable = newValue;
  405.         firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue, newValue);
  406.         repaint();
  407.     }
  408.  
  409.     /**
  410.      * Returns true if the pane provides a UI widget to collapse/expand
  411.      * the divider.
  412.      *
  413.      * @return true if the split pane provides a collapse/expand widget
  414.      */
  415.     public boolean isOneTouchExpandable() {
  416.         return oneTouchExpandable;
  417.     }
  418.  
  419.     /**
  420.      * Sets the last location the divider was at to
  421.      * <code>newLastLocation</code>.
  422.      *
  423.      * @param newLastLocation an int specifying the last divider location
  424.      *        in pixels, from the left (or upper) edge of the pane to the 
  425.      *        left (or upper) edge of the divider
  426.      * @beaninfo
  427.      *        bound: true
  428.      *  description: The last location the divider was at.
  429.      */
  430.     public void setLastDividerLocation(int newLastLocation) {
  431.         int               oldLocation = lastDividerLocation;
  432.  
  433.         lastDividerLocation = newLastLocation;
  434.         firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldLocation,
  435.                            newLastLocation);
  436.     }
  437.     
  438.     /**
  439.      * Returns the last location the divider was at.
  440.      *
  441.      * @return an int specifying the last divider location as a count
  442.      *       of pixels from the left (or upper) edge of the pane to the 
  443.      *       left (or upper) edge of the divider
  444.      */
  445.     public int getLastDividerLocation() {
  446.         return lastDividerLocation;
  447.     }
  448.  
  449.     /**
  450.      * Sets the orientation, or how the splitter is divided. The options
  451.      * are:<ul>
  452.      * <li>JSplitPane.VERTICAL_SPLIT  (above/below orientation of components)
  453.      * <li>JSplitPane.HORIZONTAL_SPLIT  (left/right orientation of components)
  454.      * </ul>
  455.      *
  456.      * @param orientation an int specifying the orientation
  457.      * @beaninfo
  458.      *        bound: true
  459.      *  description: The orientation, or how the splitter is divided.
  460.      */
  461.     public void setOrientation(int orientation) {
  462.         if (orientation != VERTICAL_SPLIT && orientation != HORIZONTAL_SPLIT) {
  463.            throw new IllegalArgumentException("JSplitPane: orientation must be one of JSplitPane.VERTICAL_SPLIT or JSplitPane.HORIZONTAL_SPLIT");
  464.         }
  465.  
  466.         int           oldOrientation = this.orientation;
  467.  
  468.         this.orientation = orientation;
  469.         firePropertyChange(ORIENTATION_PROPERTY, oldOrientation, orientation);
  470.     }
  471.  
  472.     /**
  473.      * Returns the orientation.
  474.      * 
  475.      * @return an int giving the orientation
  476.      * @see #setOrientation
  477.      */
  478.     public int getOrientation() {
  479.         return orientation;
  480.     }
  481.  
  482.     /**
  483.      * Sets whether or not the child components are continuously
  484.      * redisplayed and layed out during user intervention.
  485.      *
  486.      * @param newContinuousLayout  a boolean, true if the components
  487.      *        are continuously redrawn as the divider changes position
  488.      * @beaninfo
  489.      *        bound: true
  490.      *  description: Whether or not the child components are
  491.      *               continuously redisplayed and layed out during
  492.      *               user intervention.
  493.      */
  494.     public void setContinuousLayout(boolean newContinuousLayout) {
  495.         boolean           oldCD = continuousLayout;
  496.  
  497.         continuousLayout = newContinuousLayout;
  498.         firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldCD,
  499.                            newContinuousLayout);
  500.     }
  501.  
  502.     /**
  503.      * Returns true if the child comopnents are continuously redisplayed and
  504.      * layed out during user intervention.
  505.      *
  506.      * @return true if the components are continuously redrawn as the
  507.      *         divider changes position
  508.      */
  509.     public boolean isContinuousLayout() {
  510.         return continuousLayout;
  511.     }
  512.  
  513.     /**
  514.      * Messaged to relayout the JSplitPane based on the preferred size
  515.      * of the children components.
  516.      */
  517.     public void resetToPreferredSizes() {
  518.         SplitPaneUI         ui = getUI();
  519.  
  520.         if (ui != null) {
  521.             ui.resetToPreferredSizes();
  522.         }
  523.     }
  524.  
  525.     /**
  526.      * Sets the divider location as a percentage of the JSplitPane's size.
  527.      *
  528.      * @param proportionalLocation  a double-precision floating point value that
  529.      *        specifies a percentage, from zero (top/left) to 1.0 (bottom/right)
  530.      * @exception IllegalArgumentException if the specified location is < 0
  531.      *            or > 1.0
  532.      * @beaninfo
  533.      *  description: The location of the divider.
  534.      */
  535.     public void setDividerLocation(double proportionalLocation) {
  536.         if (proportionalLocation < 0.0 || 
  537.            proportionalLocation > 1.0) {
  538.             throw new IllegalArgumentException("proportional location must be between 0.0 and 1.0.");
  539.         }
  540.         if (getOrientation() == VERTICAL_SPLIT) {
  541.             setDividerLocation((int)((double)(getHeight() - getDividerSize()) *
  542.                                      proportionalLocation));
  543.         } else {
  544.             setDividerLocation((int)((double)(getWidth() - getDividerSize()) *
  545.                                      proportionalLocation));
  546.         }
  547.     }
  548.  
  549.     /**
  550.      * Sets the location of the divider. This is passed off to the 
  551.      * look and feel implementation.
  552.      *
  553.      * @param location an int specifying a UI-specific value (typically a 
  554.      *        pixel count)
  555.      */
  556.     public void setDividerLocation(int location) {
  557.         SplitPaneUI         ui = getUI();
  558.  
  559.         if (ui != null) {
  560.             ui.setDividerLocation(location);
  561.         }
  562.     }
  563.  
  564.     /**
  565.      * Returns the location of the divider from the look and feel
  566.      * implementation.
  567.      *
  568.      * @return an int specifying a UI-specific value (typically a 
  569.      *         pixel count)
  570.      */
  571.     public int getDividerLocation() {
  572.         SplitPaneUI         ui = getUI();
  573.  
  574.         if (ui != null) {
  575.             return ui.getDividerLocation();
  576.         }
  577.         return -1;
  578.     }
  579.  
  580.  
  581.     /**
  582.      * Returns the minimum location of the divider from the look and feel
  583.      * implementation.
  584.      *
  585.      * @return an int specifying a UI-specific value for the minimum
  586.      *         location (typically a pixel count)
  587.      * @beaninfo
  588.      *  description: The minimum location of the divider from the L&F.
  589.      */
  590.     public int getMinimumDividerLocation() {
  591.         SplitPaneUI         ui = getUI();
  592.  
  593.         if (ui != null) {
  594.             return ui.getMinimumDividerLocation();
  595.         }
  596.         return -1;
  597.     }
  598.  
  599.  
  600.     /**
  601.      * Returns the maximum location of the divider from the look and feel
  602.      * implementation.
  603.      *
  604.      * @return an int specifying a UI-specific value for the maximum
  605.      *         location (typically a pixel count)
  606.      */
  607.     public int getMaximumDividerLocation() {
  608.         SplitPaneUI         ui = getUI();
  609.  
  610.         if (ui != null) {
  611.             return ui.getMaximumDividerLocation();
  612.         }
  613.         return -1;
  614.     }
  615.  
  616.     /**
  617.      * Removes the child component, <code>component</code> from the
  618.      * pane. Resets the leftComponent or rightComponent instance
  619.      * variable, as necessary.
  620.      * 
  621.      * @param component the Component to remove
  622.      */
  623.     public void remove(Component component) {
  624.         if (component == leftComponent) {
  625.             leftComponent = null;
  626.         } else if (component == rightComponent) {
  627.             rightComponent = null;
  628.         }
  629.         super.remove(component);
  630.     }
  631.  
  632.     /**
  633.      * Removes the Component at the specified index. Updates the
  634.      * leftComponent and rightComponent ivars (instance variables) 
  635.      * as necessary, and then messages super.
  636.      *
  637.      * @param index an int specifying the component to remove, where
  638.      *        0 specifies the left/top component and 1 specifies the 
  639.      *        bottom/right component
  640.      */
  641.     public void remove(int index) {
  642.         Component    comp = getComponent(index);
  643.  
  644.         if (comp == leftComponent) {
  645.             leftComponent = null;
  646.         } else if (comp == rightComponent) {
  647.             rightComponent = null;
  648.         }
  649.         super.remove(index);
  650.     }
  651.  
  652.     /**
  653.      * Removes all the child components from the receiver. Resets the
  654.      * leftComonent and rightComponent instance variables.
  655.      */
  656.     public void removeAll() {
  657.         leftComponent = rightComponent = null;
  658.         super.removeAll();
  659.     }
  660.  
  661.     /**
  662.      * If <code>constraints</code> identifies the left/top or
  663.      * right/bottom child component, and a component with that identifier
  664.      * was previously added, it will be removed and then <code>comp</code>
  665.      * will be added in its place. If <code>constraints</code> is not
  666.      * one of the known identifers the layout manager may throw an
  667.      * IllegalArgumentException.
  668.      * <p>
  669.      * The possible constraints objects (Strings) are:<ul>
  670.      * <li>JSplitPane.TOP
  671.      * <li>JSplitPane.LEFT
  672.      * <li>JSplitPane.BOTTOM
  673.      * <li>JSplitPane.RIGHT
  674.      * </ul>
  675.      * If the constraints object is null, the component is added in the
  676.      * first available position (left/top if open, else right/bottom).
  677.      * 
  678.      * @param comp        the component to add
  679.      * @param constraints an Object specifying the layout constraints 
  680.      *                    (position) for this component
  681.      * @param index       an int specifying the index in the container's
  682.      *                    list.
  683.      * @exception IllegalArgumentException thrown if the constraints object
  684.      *            does not match an existing component
  685.      * @see java.awt.Container#addImpl(Component, Object, int)
  686.      */
  687.     protected void addImpl(Component comp, Object constraints, int index) 
  688.     {
  689.         Component             toRemove;
  690.  
  691.         if (constraints != null && !(constraints instanceof String)) {
  692.             throw new IllegalArgumentException("cannot add to layout: constraint must be a string (or null)");
  693.         }
  694.  
  695.         /* If the constraints are null and the left/right component is
  696.            invalid, add it at the left/right component. */
  697.         if (constraints == null) {
  698.             if (getLeftComponent() == null) {
  699.                 constraints = JSplitPane.LEFT;
  700.             } else if (getRightComponent() == null) {
  701.                 constraints = JSplitPane.RIGHT;
  702.             }
  703.         }
  704.             
  705.         /* Find the Component that already exists and remove it. */
  706.         if (constraints != null && (constraints.equals(JSplitPane.LEFT) ||
  707.                                    constraints.equals(JSplitPane.TOP))) {
  708.             toRemove = getLeftComponent();
  709.             if (toRemove != null) {
  710.                 remove(toRemove);
  711.             }
  712.             leftComponent = comp;
  713.             index = -1;
  714.         } else if (constraints != null && (constraints.equals(JSplitPane.RIGHT) ||
  715.                                       constraints.equals(JSplitPane.BOTTOM))) {
  716.             toRemove = getRightComponent();
  717.             if (toRemove != null) {
  718.                 remove(toRemove);
  719.             }
  720.             rightComponent = comp;
  721.             index = -1;
  722.         } else if (constraints != null &&
  723.                 constraints.equals(JSplitPane.DIVIDER)) {
  724.             index = -1;
  725.         }
  726.         /* LayoutManager should raise for else condition here. */
  727.  
  728.         super.addImpl(comp, constraints, index);
  729.     }
  730.  
  731.     /**
  732.      * Subclassed to message the UI with finishedPaintingChildren after
  733.      * super has been messaged, as well as painting the border.
  734.      *
  735.      * @param g the Graphics context within which to paint
  736.      */
  737.     protected void paintChildren(Graphics g) {
  738.         super.paintChildren(g);
  739.  
  740.         SplitPaneUI        ui = getUI();
  741.  
  742.         if (ui != null) {
  743.             Graphics           tempG = g.create();
  744.             ui.finishedPaintingChildren(this, tempG);
  745.             tempG.dispose();
  746.         }
  747.     }
  748.  
  749. /////////////////
  750. // Accessibility support
  751. ////////////////
  752.  
  753.     /**
  754.      * Get the AccessibleContext associated with this JComponent
  755.      *
  756.      * @return the AccessibleContext of this JComponent
  757.      * @beaninfo
  758.      *       expert: true
  759.      *  description: The AccessibleContext associated with this Label.
  760.      */
  761.     public AccessibleContext getAccessibleContext() {
  762.         if (accessibleContext == null) {
  763.             accessibleContext = new AccessibleJSplitPane();
  764.         }
  765.         return accessibleContext;
  766.     }
  767.  
  768.     /**
  769.      * The class used to obtain the accessible role for this object.
  770.      * <p>
  771.      * Warning: serialized objects of this class will not be compatible with
  772.      * future swing releases.  The current serialization support is appropriate
  773.      * for short term storage or RMI between Swing1.0 applications.  It will
  774.      * not be possible to load serialized Swing1.0 objects with future releases
  775.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  776.      * baseline for the serialized form of Swing objects.
  777.      */
  778.     protected class AccessibleJSplitPane extends AccessibleJComponent 
  779.         implements AccessibleValue {
  780.  
  781.         /**
  782.          * Get the state set of this object.
  783.          *
  784.          * @return an instance of AccessibleState containing the current state 
  785.          * of the object
  786.          * @see AccessibleState
  787.          */
  788.         public AccessibleStateSet getAccessibleStateSet() {
  789.             AccessibleStateSet states = super.getAccessibleStateSet();
  790.             // FIXME: [[[WDW - Should also add BUSY if this implements
  791.             // Adjustable at some point.  If this happens, we probably
  792.             // should also add actions.]]]
  793.             if (getOrientation() == VERTICAL_SPLIT) {
  794.                 states.add(AccessibleState.VERTICAL);
  795.             } else {
  796.                 states.add(AccessibleState.HORIZONTAL);
  797.             }
  798.             return states;
  799.         }
  800.     
  801.         /**
  802.          * Get the AccessibleValue associated with this object if one
  803.          * exists.  Otherwise return null.
  804.          */
  805.         public AccessibleValue getAccessibleValue() {
  806.             return this;
  807.         }
  808.  
  809.         /**
  810.          * Get the accessible value of this object.
  811.          *
  812.          * @return a localized String describing the value of this object
  813.          */
  814.         public Number getCurrentAccessibleValue() {
  815.             return new Integer(getDividerLocation());
  816.         }
  817.     
  818.         /**
  819.          * Set the value of this object as a Number.
  820.          *
  821.          * @return True if the value was set.
  822.          */
  823.         public boolean setCurrentAccessibleValue(Number n) {
  824.             if (n instanceof Integer) {
  825.                 setDividerLocation(n.intValue());
  826.                 return true;
  827.             } else {
  828.                 return false;
  829.             }
  830.         }
  831.     
  832.         /**
  833.          * Get the minimum accessible value of this object.
  834.          *
  835.          * @return The minimum value of this object.
  836.          */
  837.         public Number getMinimumAccessibleValue() {
  838.             return new Integer(getUI().getMinimumDividerLocation());
  839.         }
  840.     
  841.         /**
  842.          * Get the maximum accessible value of this object.
  843.          *
  844.          * @return The maximum value of this object.
  845.          */
  846.         public Number getMaximumAccessibleValue() {
  847.             return new Integer(getUI().getMaximumDividerLocation());
  848.         }
  849.     
  850.         /**
  851.          * Get the role of this object.
  852.          *
  853.          * @return an instance of AccessibleRole describing the role of 
  854.          * the object
  855.          * @see AccessibleRole
  856.          */
  857.         public AccessibleRole getAccessibleRole() {
  858.             return AccessibleRole.SPLIT_PANE;
  859.         }
  860.     } // inner class AccessibleJSplitPane
  861. }
  862.